<?php
/* 
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of RQLFork
 *
 * @author Admin
 */

class RQLFork extends RQLNode {
    public $branches;
    public $mode;
    protected $last_insertion = 0;
    protected $last_deletion = 0;
    protected $selection_flag = false;
 

    public function  __construct($mode, $branches) {
        $this->mode = $mode;
        $this->branches = $branches;
    }

    public function getSelect($parent = null, $acl = QConst::RQL_SELECT) {
        $f = array();
        for($i=0;$i<count($this->branches);$i++) {
            $branch = $this->branches[$i];
            $f = array_merge($f, $branch->getSelect($parent, $acl));
        }
        
        if ($this->selection_flag) {
            $f[] = $this->rid.'child';
            $f[] = $this->rid.'child_id';
        }

        $f = array_unique($f);
        return $f;
    }


    public function getWhere($parent = null, $acl = RQL::ACL_SELECT, $child = null) {
        $w = array();
        $ids = array();
        $parent_link = 'TRUE';
        $obranch_type = null;
        if ($child == null) {
            $this->mode = '||';
        }

        // связь с парентом
        if ($parent != null) {
//            $parent_link = "{$parent->rid}.child_id = {$this->rid}.parent_id AND {$parent->rid}.child = {$this->rid}.parent";
        }

        // ограничения удовлетворяющих описанию ветвления записей
        for($i=0;$i<count($this->branches);$i++) {
            $branch = $this->branches[$i];
            if ($parent != null) $branch->unshift($parent);
            if ($child != null) $branch->add_node($child);
            $ids = $branch->get_branch_query($acl, $this->mode);
            if ($ids) {
                $sub = $ids;
                $w [] = $sub;
            }
            $ids = null;
        }

        if ($this->mode == '&&') {
            $joins = 'SELECT relations.id FROM `relations`';
            // making joins ]:->
            for($i=0;$i<count($w);$i++) {
                $join_name = $this->rid.'_join'.$i;
                $joins .= ' JOIN ('.$w[$i].') as '.$join_name.' ON '.$join_name.'.child = relations.child AND '.$join_name.'.child_id = relations.child_id ';
            }
            return "{$this->rid}.id IN ($joins)";
        }

        return "({$this->rid}.id IN (".implode(") OR ({$this->rid}.id IN (", $w).")))";
    }

    public function drop_operations_data() {
        for($i=0;$i<count($this->branches);$i++) {
            $this->branches[$i]->drop_operations_data();
        }
    }

    public function getFrom($parent = null, $acl = QConst::RQL_SELECT) {
        if (!$this->rid) $this->regenerate_rid();
        return array("relations as {$this->rid}");
    }

    public function regenerate_id($parent = null, $force = false) {
        if ($this->rid && !$force) return $this->rid;
        if ($parent == null) $name = 'fork';
        else $name = $parent->getName().'_fork';
        $rid = $name.'_'.rand(1, 10000);
        if ($rid == $this->rid) $this->regenerate_rid();
        else $this->rid = $rid;
    }

    public function getLasts() {
        $ret = array();
        foreach($this->branches as $branch) {
            $ret[] = $branch->get_last_node();
        }

        return $ret;
    }

    public function get_real_name($alias) {
        for($i=0;$i<count($this->branches); $i++) {
            $rn = $this->branches[$i]->get_real_name($alias);
            if ($rn !== false) return $rn;
        }
    }

    public function getName() {
        return 'fork';
    }

    public function getUpdate() {
        $res = array();
        for($i=0;$i<count($this->branches);$i++) {
            $update = $this->branches[$i]->getUpdate();
            if (count($update) > 0) {
                $res = array_merge($res, $update);
            }
        }
        return $res;
    }

    public function get_next_insertion() {
        for($this->last_insertion; $this->last_insertion < count($this->branches);$this->last_insertion++) {
            $outcome = $this->branches[$this->last_insertion];
            $sub_insertion = $outcome->get_next_insertion();
            if ($sub_insertion !== false) return $sub_insertion;
        }
        return false;
    }

    public function get_next_deletion() {
        for($this->last_deletion; $this->last_deletion < count($this->branches);$this->last_deletion++) {
            $outcome = $this->branches[$this->last_deletion];
            $sub_deletion = $outcome->get_next_deletion();
            if ($sub_deletion !== false) return $sub_deletion;
        }
        return false;
    }

    public function get_node_path($name, $skip=0) {
        for($i=0;$i<count($this->branches);$i++) {
            $res = $this->branches[$i]->get_node_path($name);
            if ($res !== false && is_array($res)) {
                if ($skip == 0) return $res;
                else $skip--;
            }
        }
        return false;
    }

    public function drop_selection_data() {
        for($i=0;$i<count($this->branches);$i++) {
            $this->branches[$i]->drop_selection_data();
        }

    }

    public function get_selected_fields($parent = null) {
        $this->regenerate_id($parent);
        if ($this->selection_flag) {
            return array($this->rid.'.child', $this->rid.'.child_id');
        }
        return array();
        $ret = array();
        for($i=0;$i<count($this->branches);$i++) {
            if ($parent != null) {
                $virt = clone $parent;
                if ($this->operation == '||') {
                    $branch_parent_node = $this->branches[$i]->get_parent_node();
                    $virt->rid .= '_'.$branch_parent_node->getName();
                }
                else $virt->rid .= '_'.$i;
            } else {
                $virt = null;
            }

            $fields = $this->branches[$i]->get_selected_fields($virt);
            if (count($fields) > 0) $ret = array_merge($ret, $fields);
        }
        return $ret;
    }

    public function setOperation($op) {
        if ($op == '$') $this->selection_flag = true;
        else throw new Exception('Fork does not support operation `'.$op.'`');
    }

    public function add_selection_field($name) {
        for($i=0;$i<count($this->branches);$i++) {
            $last = $this->branches[$i]->get_last_node();
            $last->add_selection_field($name);
            $this->branches[$i]->set_last_node($last);
        }
    }

    public function update_description_by_real_name($name, $field, $operator, $value) {
        for($i=0;$i<count($this->branches);$i++) {
            if ($this->branches[$i]->update_description_by_real_name($name, $field, $operator, $value)) {
                return true;
            }
        }
        return false;
    }

    public function must_select() {
        for($i=0;$i<count($this->branches);$i++) {
            if ($this->branches[$i]->must_select()) return true;
        }
    }

    public function must_insert() {
        for($i=0;$i<count($this->branches);$i++) {
            if ($this->branches[$i]->must_insert()) return true;
        }
    }

    public function must_delete() {
        for($i=0;$i<count($this->branches);$i++) {
            if ($this->branches[$i]->must_delete()) return true;
        }
    }

    public function get_selected_real_names($parent = null) {
        $ret = array();
        for($i=0;$i<count($this->branches);$i++) {
            $node = $this->branches[$i];
            $fields = $node->get_selected_real_names($parent);
            if (!$fields) continue;
            if (count($fields) > 0) $ret = array_merge($ret, $fields);
            $parent = $node;
        }
        return $ret;
    }

 }
?>
